#include <cmath>

using namespace std;

#include "OgreBitwise.h"
#include "VectorField2.h"
#include "FlowSimUtil.h"

using namespace FlowSim;
using namespace Ogre;

VectorField2::VectorField2(int size):_size(size)
{
  //allocate data
  _data = new Ogre::Vector2[size*size];
}

VectorField2::~VectorField2()
{
  delete _data;
}

Ogre::Vector2* VectorField2::getData()
{
  return _data;
}

void VectorField2::setVec(int x, int y, Ogre::Real vx, Ogre::Real vy)
{
  _data[A_INDEX(x,y,_size)].x = vx;
  _data[A_INDEX(x,y,_size)].y = vy;
  //_data[A_INDEX(x,y,_size)].normalise();
}

/**
 *This method creates a simple 2D vector field  based on the equation:
 *F = (-y,x)/5. 
 **/
auto_ptr<VectorField2> VectorField2::testField(int size)
{
  auto_ptr<VectorField2> vf(new VectorField2(size));
  Ogre::Vector2* data=vf->getData();
  //Ogre::Vector2* data = vf->getData();
  Ogre::Real x = -size/2;
  Ogre::Real y = -size/2;
  Ogre::Real len;
  int weird = 1;
  for(int i = 0; i < size; i++)
    {
      for(int j = 0; j < size; j++)
	{
	  //vf->setVec(i,j,0.0,0.0);
// 	  len = 1.0/sqrt((y/5)*(y/5)+(x/5)*(x/5));
// 	  if(len > 0.00000001)
//  	    {
//  	      vf->setVec(i,j,(-y/5)*len,(x/5)*len); //set the vector at position i,j based on the definition of u(x,y)
//  	    }
//  	  else
// 	    vf->setVec(i,j,0,0);
	  //vf->setVec(i,j,(-y/5),(x/5));
	  vf->setVec(i,j,-y,x);
	  //data[A_INDEX(i,j,size)].x = -y/weird;
	  //data[A_INDEX(i,j,size)].y = x/weird;
	  //data[A_INDEX(i,j,size)].normalise();
	  //vf->setVec(i,j,0.1*x,0.1*y);
	  //vf->setVec(i,j,200.0,0.0);
	  //vf->setVec(i,j,0.0,0.0);
	  y+=1.0;
	}
      y = -size/2;
      x+=1.0;
    }
  
  return vf;
} 
void VectorField2::testGpuField(const Ogre::TexturePtr &tex,int size)
{
  Real x = -size/2;
  Real y = -size/2;
  Real offset = 1024/2;
  HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();
  pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
  const PixelBox& pixelBox = pixelBuffer->getCurrentLock();
  uint16* pDest = static_cast<uint16*>(pixelBox.data);
  Real r,g;
  for(int i=0; i< size; i++)
    {
      for(int j=0; j < size; j++)
	{
	  //r = 1.0; g = 10.0;
	  r = -y; g=x; //remember the vector equation is f(x,y) = -yi + xj;
	  //cout << "r,g before: " << r << " " << g << endl; 
	  //r = r/offset;
	  //g = g/offset;
	  //cout << "r,g after: " << r << " " << g << endl;
	  *pDest++ = Bitwise::floatToHalf(r); //B, move r into [0.0,1.0]
	  *pDest++ = Bitwise::floatToHalf(g); //G, move g into [0.0,1.0]
	  *pDest++ = Bitwise::floatToHalf(0.0); //R, nothing for B, since we're working in 2D.
	  *pDest++ = Bitwise::floatToHalf(1.0); //A, Alpha is always 1.0
	  y+=1.0;
	}
      y = -size/2;
      x+=1.0;
    }
  pixelBuffer->unlock();
}

void VectorField2::blankGpuField(const TexturePtr &tex, int size)
{
  HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();
  pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
  const PixelBox& pixelBox = pixelBuffer->getCurrentLock();
  uint16* pDest = static_cast<uint16*>(pixelBox.data);
  Real rd;
  for(int i=0; i< size; i++)
    {
      for(int j=0; j < size; j++)
	{
	  rd = Math::RangeRandom(0.5,1.0);
	  rd = 0.0;
	  //cout << "RD: " << rd << endl;
	  *pDest++ = Bitwise::floatToHalf(0.0); //B, move r into [0.0,1.0]
	  *pDest++ = Bitwise::floatToHalf(rd); //G, move g into [0.0,1.0]
	  *pDest++ = Bitwise::floatToHalf(rd); //R, nothing for B, since we're working in 2D.
	  *pDest++ = Bitwise::floatToHalf(1.0); //A, Alpha is always 1.0
	}
    }
  pixelBuffer->unlock();
}


void VectorField2::testGpuField8(const Ogre::TexturePtr &tex,int size)
{
  Real x = -size/2;
  Real y = -size/2;
  Real offset = size/2;
  HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();
  pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
  const PixelBox& pixelBox = pixelBuffer->getCurrentLock();
  uint8* pDest = static_cast<uint8*>(pixelBox.data);
  Real r,g;
  for(int i=0; i< size; i++)
    {
      for(int j=0; j < size; j++)
	{
	  *pDest++ = 0;
	  *pDest++ = 0;
	  *pDest++ = 255;
	  *pDest++ = 255;
	  y+=1.0;
	}
      y = -size/2;
      x+=1.0;
    }
  pixelBuffer->unlock();
}
/**
 *This methods creates a blank vector field.
 **/
auto_ptr<VectorField2> VectorField2::blankField(int size)
{
  auto_ptr<VectorField2> vf(new VectorField2(size));
  return vf;
}

